package com.css.zfzx.fxpg.modules.evaluationmap.casualty.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.css.bpm.platform.utils.*;
import com.css.zfzx.fxpg.common.utils.AreaBoundaryUtil;
import com.css.zfzx.fxpg.common.utils.BeanUtil;
import com.css.zfzx.fxpg.common.utils.CheckObjFields;
import com.css.zfzx.fxpg.modules.boundary.Point;
import com.css.zfzx.fxpg.modules.boundary.repository.BoundaryNativeRepository;
import com.css.zfzx.fxpg.modules.boundary.repository.entity.BoundaryEntity;
import com.css.zfzx.fxpg.modules.boundary.viewobjects.BoundaryQueryParams;
import com.css.zfzx.fxpg.modules.evaluationmap.casualty.repository.FxCasualtyEvaluationMapImport;
import com.css.zfzx.fxpg.modules.evaluationmap.casualty.repository.FxCasualtyEvaluationMapNativeRepository;
import com.css.zfzx.fxpg.modules.evaluationmap.casualty.repository.entity.FxCasualtyEvaluationMapEntity;
import com.css.zfzx.fxpg.modules.evaluationmap.casualty.service.FxCasualtyEvaluationMapService;
import com.css.zfzx.fxpg.modules.evaluationmap.casualty.viewobjects.FxCasualtyEvaluationMapQueryParams;
import com.css.zfzx.fxpg.modules.evaluationmap.casualty.viewobjects.FxCasualtyEvaluationMapVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @author andy
 * @date 2021-01-26
 */
@Service
@Slf4j
public class FxCasualtyEvaluationMapServiceImpl implements FxCasualtyEvaluationMapService {

	@Autowired
    private com.css.zfzx.fxpg.modules.evaluationmap.casualty.repository.FxCasualtyEvaluationMapRepository FxCasualtyEvaluationMapRepository;
    @Autowired
    private FxCasualtyEvaluationMapNativeRepository fxCasualtyEvaluationMapNativeRepository;

    @Autowired
    private FxCasualtyEvaluationMapImport fxCasualtyEvaluationMapImport;

    @Override
    public JSONObject queryFxCasualtyEvaluationMaps(FxCasualtyEvaluationMapQueryParams queryParams, int curPage, int pageSize) {
        Page<FxCasualtyEvaluationMapEntity> fxCasualtyEvaluationMapEntityPage = this.fxCasualtyEvaluationMapNativeRepository.queryFxCasualtyEvaluationMaps(queryParams, curPage, pageSize);
        JSONObject jsonObject = PlatformPageUtils.formatPageData(fxCasualtyEvaluationMapEntityPage);
        return jsonObject;
    }

    @Override
    public JSONObject queryFxCasualtyEvaluationMapsByFileName(FxCasualtyEvaluationMapQueryParams queryParams, int curPage, int pageSize, String sort, String order) {
        if (!PlatformObjectUtils.isEmpty(sort) && sort.length() > 0) {
            sort = CheckObjFields.propertyChange(sort);
        }
        Page<FxCasualtyEvaluationMapEntity> fxCasualtyEvaluationMapEntityPage = this.fxCasualtyEvaluationMapNativeRepository.queryFxCasualtyEvaluationMapsByFileName(queryParams, curPage, pageSize, sort, order);
        JSONObject jsonObject = PlatformPageUtils.formatPageData(fxCasualtyEvaluationMapEntityPage);
        return jsonObject;
    }

    @Override
    public FxCasualtyEvaluationMapEntity getFxCasualtyEvaluationMap(String id) {
        FxCasualtyEvaluationMapEntity fxCasualtyEvaluationMapEntity = this.FxCasualtyEvaluationMapRepository.findById(id).orElse(null);
        return fxCasualtyEvaluationMapEntity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FxCasualtyEvaluationMapEntity saveFxCasualtyEvaluationMap(FxCasualtyEvaluationMapEntity fxCasualtyEvaluationMapEntity) {
        String uuid = UUIDGenerator.getUUID();
        fxCasualtyEvaluationMapEntity.setUuid(uuid);
        fxCasualtyEvaluationMapEntity.setCreateUser(PlatformSessionUtils.getUserId());
        fxCasualtyEvaluationMapEntity.setCreateTime(PlatformDateUtils.getCurrentTimestamp());
        this.FxCasualtyEvaluationMapRepository.save(fxCasualtyEvaluationMapEntity);
        return fxCasualtyEvaluationMapEntity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FxCasualtyEvaluationMapEntity updateFxCasualtyEvaluationMap(FxCasualtyEvaluationMapEntity fxCasualtyEvaluationMap) {
        fxCasualtyEvaluationMap.setUpdateUser(PlatformSessionUtils.getUserId());
        fxCasualtyEvaluationMap.setUpdateTime(PlatformDateUtils.getCurrentTimestamp());
        String id = fxCasualtyEvaluationMap.getUuid();
        FxCasualtyEvaluationMapEntity one = FxCasualtyEvaluationMapRepository.findById(id).get();
        BeanUtil.copyPropertiesIgnoreNull(fxCasualtyEvaluationMap, one);
        this.FxCasualtyEvaluationMapRepository.save(one);
        return fxCasualtyEvaluationMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteQhRiskEvaluationMaps(List<String> ids) {
        List<FxCasualtyEvaluationMapEntity> qhFxCasualtyEvaluationMapList = this.FxCasualtyEvaluationMapRepository.findAllById(ids);
        if(!PlatformObjectUtils.isEmpty(qhFxCasualtyEvaluationMapList) && qhFxCasualtyEvaluationMapList.size() > 0) {
            for(FxCasualtyEvaluationMapEntity qhFxCasualtyEvaluationMap : qhFxCasualtyEvaluationMapList) {
                this.FxCasualtyEvaluationMapRepository.delete(qhFxCasualtyEvaluationMap);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFxCasualtyEvaluationMapsByFileName(List<String> fileNames) {
        for (int i = 0; i < fileNames.size(); i++) {
            FxCasualtyEvaluationMapQueryParams queryParams = new FxCasualtyEvaluationMapQueryParams();
            queryParams.setAffiliatedFileName(fileNames.get(i));
            List<FxCasualtyEvaluationMapEntity> qhFxCasualtyEvaluationMapList = this.fxCasualtyEvaluationMapNativeRepository.listFxCasualtyEvaluationMaps(queryParams);
            if(!PlatformObjectUtils.isEmpty(qhFxCasualtyEvaluationMapList) && qhFxCasualtyEvaluationMapList.size() > 0) {
                /*for(QhProbabilityEarthquakeDangerEntity qhSiteClassResult : qhSiteClassResultList) {
                    this.qhSiteClassResultRepository.delete(qhSiteClassResult);
                }*/
                //物理删
                //fxCasualtyLevelMapImport.sqlBatchDeleteEntities(qhFxCasualtyLevelMapList);
                fxCasualtyEvaluationMapImport.sqlBatchLogicDeleteEntities(qhFxCasualtyEvaluationMapList);
            }
        }
    }

    @Override
    public JSONObject getFxCasualtyEvaluationMaps(FxCasualtyEvaluationMapQueryParams queryParams) {
        List<FxCasualtyEvaluationMapEntity> qhFxCasualtyEvaluationMaps = this.fxCasualtyEvaluationMapNativeRepository.listFxCasualtyEvaluationMaps(queryParams);
        /*for (FxCasualtyEvaluationMapEntity cemEntity : qhFxCasualtyEvaluationMaps) {
            Map.Entry<String, Map<String, String>> city2areas = AreaBoundaryUtil.getCoordsByCityName(cemEntity.getProvince(), cemEntity.getCity());
            String coords = city2areas.getValue().get(cemEntity.getArea());
            cemEntity.setCoordinate(coords);
        }*/
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("data", qhFxCasualtyEvaluationMaps);
        return jsonObject;
    }

    @Override
    public JSONObject getFxCasualtyEvaluationMapsForSyntheticalDistrict(FxCasualtyEvaluationMapQueryParams queryParams) {
        List<FxCasualtyEvaluationMapEntity> qhFxCasualtyEvaluationMaps = this.fxCasualtyEvaluationMapNativeRepository.listFxCasualtyEvaluationMaps(queryParams);
        for (FxCasualtyEvaluationMapEntity cemEntity : qhFxCasualtyEvaluationMaps) {
            String coords = getBoundaries(cemEntity.getProvince(), cemEntity.getCity(), cemEntity.getArea());
            cemEntity.setCoordinate(coords);
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("data", qhFxCasualtyEvaluationMaps);
        return jsonObject;
    }
    @Autowired
    private BoundaryNativeRepository boundaryNativeRepository;
    public String getBoundaries(String province, String city, String area) {
        BoundaryQueryParams queryParams = new BoundaryQueryParams();
        queryParams.setType("1");
        queryParams.setLevel("2");
        queryParams.setProvince(province);
        queryParams.setCity(city);
        queryParams.setArea(area);
        queryParams.setName(area);
        List<BoundaryEntity> boundaryEntities = this.boundaryNativeRepository.listBoundaries(queryParams);
        if (boundaryEntities.size() == 1) {
            String coords = boundaryEntities.get(0).getCoordinate();
            if (coords == null) return "";
            coords = coords.substring(coords.indexOf("(((") + 3, coords.lastIndexOf(")))") - 1);
            coords = coords.replace(")), ((", "|");
            coords = coords.replace("), (", "#");
            coords = coords.replace(", ", ";");
            coords = coords.replace(" ", ",");
            return coords;
        }
        return "";
    }

    @Override
    public String importTIFFileData(String filePath, String province, String city, String area, String condition, double casualtyNum, int riskLevel, String coordinate, String numGridData) {
        String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length() - 4);
        // 返回的消息
        StringBuilder returnMsg = new StringBuilder();
        List<FxCasualtyEvaluationMapVo> scrVOs = new ArrayList<FxCasualtyEvaluationMapVo>();

        deleteFxCasualtyEvaluationMapData(province, city, area, condition);

        FxCasualtyEvaluationMapVo clmVO = new FxCasualtyEvaluationMapVo();
        clmVO.setProvince(province);
        clmVO.setCity(city);
        clmVO.setArea(area);
        clmVO.setAffiliatedFileName(fileName);
        clmVO.setEarthquakeRisk(condition);//(地震危险性 0:50年超越概率2%分区, 1:50年超越概率10%分区, 2:50年超越概率63%分区, 3:100年超越概率1%分区)
        clmVO.setSum(casualtyNum);//(tif文件中死亡人口数量)
        clmVO.setLevel(riskLevel);//(死亡人口数量对应的风险等级)
        clmVO.setCoordinate(coordinate);
        clmVO.setGridData(numGridData);
        clmVO.setExtend1("CGCS2000");

        scrVOs.add(clmVO);
        try {
            // 批量新增
            this.saveData(scrVOs);
            returnMsg.append("成功导入" + scrVOs.size() + "条数据.");
            return returnMsg.toString();
        } catch (RuntimeException e) {
            log.error(e.getMessage(), e);
            return "插入或更新数据出现错误: <br/>" + e.getMessage();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return "数据导入失败, 服务器内部出现异常!";
        }
    }

    private void saveData(List<FxCasualtyEvaluationMapVo> list) throws Exception {
        List<FxCasualtyEvaluationMapEntity> clms = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            FxCasualtyEvaluationMapEntity cemEntity = new FxCasualtyEvaluationMapEntity();
            FxCasualtyEvaluationMapVo clmVO = list.get(i);
            // 将VO数据映射拷贝到库表中
            BeanUtils.copyProperties(clmVO, cemEntity);
            cemEntity.setIsValid("1");
            clms.add(cemEntity);
            //saveOrUpdate(scrEntity);
        }
        fxCasualtyEvaluationMapImport.sqlBatchSaveEntities(clms);
    }

    @Override
    public void saveOrUpdate(FxCasualtyEvaluationMapEntity rlmEntity) {
        FxCasualtyEvaluationMapQueryParams queryParams = new FxCasualtyEvaluationMapQueryParams();
        queryParams.setProvince(rlmEntity.getProvince());
        queryParams.setCity(rlmEntity.getCity());
        queryParams.setArea(rlmEntity.getArea());
        List<FxCasualtyEvaluationMapEntity> clmEntities = fxCasualtyEvaluationMapNativeRepository.listFxCasualtyEvaluationMaps(queryParams);
        // 若查到数据为空，则新增
        if (CollectionUtils.isEmpty(clmEntities)) {
            this.saveFxCasualtyEvaluationMap(rlmEntity);
        } else {
            if (clmEntities.size() == 1) {
                FxCasualtyEvaluationMapEntity sourceProvinceEntity = clmEntities.get(0);
                BeanUtil.copyPropertiesIgnoreNull(rlmEntity, sourceProvinceEntity);
                this.updateFxCasualtyEvaluationMap(sourceProvinceEntity);
            } else {
                throw new RuntimeException("库中该数据最多一条，请管理员清理数据库冗余数据！");
            }
        }
    }

    private void deleteFxCasualtyEvaluationMapData(String province, String city, String area, String earthquakeRisk) {
        FxCasualtyEvaluationMapQueryParams queryParams = new FxCasualtyEvaluationMapQueryParams();
        queryParams.setProvince(province);
        queryParams.setCity(city);
        queryParams.setArea(area);
        queryParams.setEarthquakeRisk(earthquakeRisk);
        List<FxCasualtyEvaluationMapEntity> list = fxCasualtyEvaluationMapNativeRepository.listFxCasualtyEvaluationMaps(queryParams);
        if (list.size() > 0) fxCasualtyEvaluationMapImport.sqlBatchDeleteEntities(list);
    }

    @Override
    public String judgeFileParams(String[] datas) {
        String str = "";
        Set<String> set = new HashSet<String>(Arrays.asList(datas));
        if(!set.contains("A")){
            str += "A,";
        }
        if(!set.contains("B")){
            str += "B,";
        }
        if(!set.contains("C")){
            str += "C,";
        }
        return str;
    }

    private String judgeFieldParams(List<List<Object>> list) {
        String str = "";
        for (int i = 0; i < list.size(); i++) {
            List<Object> values = list.get(i);
            //for (int j = 0; j < values.size(); j++) {
            for (int j = 0; j < 2; j++) {
                if ("".equals(values.get(j))) {
                    str += "第 " + i + " 条数据第 " + j + " 个字段数据为空.<br/>";
                }
            }
        }
        return str;
    }

    @Override
    public String checkPointIsInDistrict(String province, String city, String area, String rasterCoordinate) {
        BoundaryQueryParams queryParams = new BoundaryQueryParams();
        queryParams.setType("1");
        queryParams.setLevel("2");
        queryParams.setProvince(province);
        queryParams.setCity(city);
        queryParams.setArea(area);
        queryParams.setName(area);
        List<BoundaryEntity> boundaryEntities = this.boundaryNativeRepository.listBoundaries(queryParams);
        if (boundaryEntities.size() == 1) {
            BoundaryEntity boundaryEntity = boundaryEntities.get(0);
            String coordinate = boundaryEntity.getCoordinate();
            if (coordinate == null || "".equals(coordinate)) {
                return "NoDistrictBoundaryData";
            } else {
                coordinate = coordinate.substring(coordinate.indexOf("(((") + 3, coordinate.lastIndexOf(")))"));
                coordinate = coordinate.replace(")), ((", "|");
                coordinate = coordinate.replace("), (", "#");
                List<Point[]> boundaries = new ArrayList<>();
                String[] coordinates = StringUtils.split(coordinate, "|");
                for (int j = 0; j < coordinates.length; j++) {
                    String[] subGeometries = coordinates[j].split("#");
                    for (int k = 0; k < subGeometries.length; k++) {
                        String[] lonLats = subGeometries[k].split(", ");
                        Point[] points = new Point[lonLats.length];
                        for (int i = 0;i < lonLats.length;i++) {
                            String[] lonLat = lonLats[i].split(" ");
                            Point point = new Point();
                            point.x = Double.parseDouble(lonLat[0]);
                            point.y = Double.parseDouble(lonLat[1]);
                            points[i] = point;
                        }
                        boundaries.add(points);
                    }
                }

                int flag = 0;
                List<Point[]> geometries = parseWktCoordinate(rasterCoordinate);
                for (int j = 0; j < geometries.size(); j++) {
                    Point[] rectanglePoints = geometries.get(j);
                    flag = 0;
                    for (int m = 0; m < boundaries.size(); m++) {
                        Point[] boundary = boundaries.get(m);
                        if (AreaBoundaryUtil.isPolygonsOverlap(rectanglePoints, boundary)) {
                            flag++;
                            break;
                        } else {
                            boolean f = false;
                            for (int i = 0; i < rectanglePoints.length; i++) {
                                for (int k = 0; k < boundary.length; k++) {
                                    if (checkValue(rectanglePoints[i].x, boundary[k].x) || checkValue(rectanglePoints[i].y, boundary[k].y)) {
                                        flag++;
                                        f = true;
                                        break;
                                    }
                                }
                                if (f) break;
                            }
                        }
                    }
                    if (flag == 0) return "false";
                }
            }
        } else if (boundaryEntities.size() == 0) {
            return "NoDistrictBoundaryData";
        } else {
            return "DistrictBoundaryDataRedundance";
        }
        return "true";
    }
    private List<Point[]> parseWktCoordinate(String coordinate) {

        List<Point[]> geometriesList = new ArrayList<>();

        String[] rectangles = StringUtils.split (coordinate, "|");
        for (int i = 0; i < rectangles.length; i++) {
            String[] coords = rectangles[i].split (";");
            Point[] points = new Point[coords.length];
            for (int j = 0; j < coords.length; j++) {
                String[] lonLat = coords[j].split(" ");
                double lon = Double.parseDouble(lonLat[0]), lat = Double.parseDouble(lonLat[1]);
                Point point = new Point(lon, lat);
                points[j] = point;
            }
            geometriesList.add(points);
        }
        return geometriesList;
    }
    private boolean checkValue(double value1, double value2) {
        double thresh = 30;
        double det = Math.abs(value1 - value2);
        if (det >= 1) return false;
        det *= 60;
        if (det >= 1) return false;
        det *= 60;
        if (det <= thresh) return true;
        return false;
    }

    @Override
    public Long lookUpFxCasualtyEvaluationMaps(FxCasualtyEvaluationMapQueryParams queryParams) {
        Long count = this.fxCasualtyEvaluationMapNativeRepository.lookUpFxCasualtyEvaluationMaps(queryParams);
        return count;
    }

}
